package testtiles;

import java.awt.Graphics2D;
import java.util.ArrayList;

import butines.core.game.Image;
import butines.core.game.ImageSheet;

public class Map {

	private ImageSheet tileset;
	private int numTileX;
	private int numTileY;
	private int tileWidth;
	private int tileHeight;
	private Tile[][] tiles;
	
	private int xDrawStart;
	private int yDrawStart;
	private int xDrawEnd;
	private int yDrawEnd;
	
	public Map(ImageSheet tileset, int numTileX, int numTileY) {
		if (tileset == null) {
			throw new IllegalArgumentException("Argument 'tileset' is null");
		}
		if (numTileX < 1) {
			throw new IllegalArgumentException("Argument 'numTileX' is negative or zero");
		}
		if (numTileY < 1) {
			throw new IllegalArgumentException("Argument 'numTileY' is negative or zero");
		}
		
		this.tileset = tileset;
		this.numTileX = numTileX;
		this.numTileY = numTileY;
		this.tileWidth = tileset.getImageWidth();
		this.tileHeight = tileset.getImageHeight();
		this.tiles = new Tile[numTileY][numTileX];

		init();
	}
	
	private void init() {
		for (int iy = 0; iy < numTileY; iy++) {
			for (int ix = 0; ix < numTileX; ix++) {
				int x = (tileWidth / 2) + tileWidth * ix;
				int y = (tileHeight / 2) + tileHeight * iy;
				int n = 356 + (int) (Math.random() * 4);
				tiles[iy][ix] = new Tile(ix, iy);
				tiles[iy][ix].x = x;
				tiles[iy][ix].y = y;
				tiles[iy][ix].image = tileset.getImage(n);
			}
		}
	}

	public int getNumTiles() {
		 return numTileX * numTileY;
	}
	
	public int getNumTileX() {
		return numTileX;
	}

	public void setNumTileX(int numTileX) {
		this.numTileX = numTileX;
	}

	public int getNumTileY() {
		return numTileY;
	}

	public void setNumTileY(int numTileY) {
		this.numTileY = numTileY;
	}

	public void setTile(int ix, int iy, int i) {
		tiles[iy][ix].image = tileset.getImage(i);
	}
	
	public Image getImage(int ix, int iy) {
		return tiles[iy][ix].image;
	}
	
	public Tile getTile(float x, float y) {
		int iy = Math.round((y - tileHeight / 2) / tileHeight );
		int ix = Math.round((x - tileWidth / 2) / tileWidth );
		if (iy < 0 || iy > numTileY - 1 || ix < 0 || ix > numTileX - 1) {
			return null;
		}
		return tiles[iy][ix];
	}
	
	public Tile getTile(int ix, int iy) {
		return tiles[iy][ix];
	}
	
	public int getTileWidth() {
		return tileWidth;
	}

	public void setTileWidth(int tileWidth) {
		this.tileWidth = tileWidth;
	}

	public int getTileHeight() {
		return tileHeight;
	}

	public void setTileHeight(int tileHeight) {
		this.tileHeight = tileHeight;
	}

	public void draw(Graphics2D g2d, int ix, int iy) {
		float sx = ix*tileWidth + tileWidth/2;
		float sy = iy*tileHeight + tileHeight/2;
		Image img = getImage(ix, iy);
		img.draw(g2d, sx, sy);
	}
	
	
	public void draw(Graphics2D g2d) {
		for (int y = yDrawStart; y < yDrawEnd; y++) {
			for (int x = xDrawStart; x < xDrawEnd; x++) {
				draw(g2d, x, y);
			}
		}
	}
	
	public void setVisibleTiles(float ox, float oy, int vw, int vh) {
		xDrawStart = (int)(ox / tileWidth);
		yDrawStart = (int)(oy / tileHeight);
		xDrawEnd = xDrawStart + (vw / tileWidth);
		yDrawEnd = yDrawStart + (vh / tileHeight);
		
		xDrawStart = Math.max(xDrawStart, 0);
		yDrawStart = Math.max(yDrawStart, 0);
		
		xDrawEnd = Math.min(xDrawEnd + 2, numTileX);
		yDrawEnd = Math.min(yDrawEnd + 2, numTileY);
	}
	
	public int getXDrawStart() {
		return xDrawStart;
	}

	public int getYDrawStart() {
		return yDrawStart;
	}

	public int getXDrawEnd() {
		return xDrawEnd;
	}

	public int getYDrawEnd() {
		return yDrawEnd;
	}

	public Tile searchNextAvailableTile(Tile tile) {
		int n = 3;
		int j = 1;
//		System.out.println("\n>>>");
		while (n <= 7) {
			int ix = tile.getIx() - j;
			int iy = tile.getIy() - j;
			
			Tile found = null;
			
			ix = Math.min(numTileX - 1, Math.max(0, ix));
			iy = Math.min(numTileY - 1, Math.max(0, iy));
			
			// top
//			System.out.print("top: ");
			for (int i = 0; i < n; i++) {
//				System.out.print("(" + (ix + i) +" " + iy + ") ");
				found = tiles[iy][ix + i];
				if (found.isUsed() == false) {
					return found;
				}
			}
			
			// left
//			System.out.print("\nleft: ");
			for (int i = 0; i < n; i++) {
//				System.out.print("(" + (ix) +" " + (iy+i) + ") ");
				found = tiles[iy + i][ix];
				if (found.isUsed() == false) {
					return found;
				}
			}
			
			// bottom
//			System.out.print("\nbottom: ");
			for (int i = 0; i < n; i++) {
//				System.out.print("(" + (ix+i) +" " + (iy+(n-1)) + ") ");
				found = tiles[iy + (n-1)][ix + i];
				if (found.isUsed() == false) {
					return found;
				}
			}
			// right
//			System.out.print("\nright: ");
			for (int i = 0; i < n; i++) {
//				System.out.print("(" + (ix+(n-1)) +" " + (iy+i) + ") ");
				found = tiles[iy + i][ix + (n-1)];
				if (found.isUsed() == false) {
					return found;
				}
			}
			
			n = n + 2;
			j = j - 1;
		}
//		System.out.println("\n<<<");			
		return null;
	}
	
	public class Tile {
		
		private int ix;
		private int iy;
		
		private float x;
		private float y;
		private Image image;
		private boolean solid;
		private ArrayList<Unit> units = new ArrayList<Unit>();
		
		public Tile(int ix, int iy) {
			this.ix = ix;
			this.iy = iy;
		}
		
		public Image getImage() {
			return image;
		}
		
		public void draw(Graphics2D g2d) {
			image.draw(g2d, x, y);
		}
		
		public float getLeft() {
			return x - tileWidth / 2;
		}
		
		public float getTop() {
			return y - tileHeight / 2;
		}
		
		public float getWidth() {
			return tileWidth;
		}
		
		public float getHeight() {
			return tileHeight;
		}
		
		public float getX() {
			return x;
		}
		
		public float getY() {
			return y;
		}
		
		public int getIx() {
			return ix;
		}

		public int getIy() {
			return iy;
		}
		
		public boolean isSolid() {
			return solid;
		}

		public void setSolid(boolean solid) {
			this.solid = solid;
		}
		
		public boolean isUsed() {
			return units.size() > 0;
		}

		public int count() {
			return units.size();
		}
		
	}
	
}